﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using System.IO;

namespace Assets.Scripts.LDS
{

    sealed class Scene
    {
        /// <summary>
        /// Prevents a default instance of the 
        /// <see cref="Singleton"/> class from being created.
        /// </summary>
        private static Scene _instance = null;

        /// <summary>
        /// Gets the instance.
        /// </summary>
        public static Scene Instance
        {
            get { return _instance ?? (_instance = new Scene()); }
        }

        private TextSemGraphManager m_textSemGraphManager;//generator
        private SceneGenerator m_sceneGenerator;//generator
        private List<SceneSemGraph> m_variations;//generator

        int m_activeVarationId;
        int m_previewNum;
        int m_initPreviewNum;
        int m_activeIdx;


        MetaModel roomModel;
        bool m_resetPreview;  // if scene is right after an evolution step

        private Scene()
        {
            InitParams();

            m_textSemGraphManager = new TextSemGraphManager();
            m_sceneGenerator = new SceneGenerator();
            m_variations = new List<SceneSemGraph>();
        }

        public SceneSemGraph getSsg(int varationId = 0)
        {
            if (m_variations.Count <= varationId)
            {
                TextDialog.textDebug("varationId OutofRange");
                return null;
            }
            else return m_variations[varationId];
        }


        private void InitParams()
        {

            m_previewNum = Params.previewNum;
            m_initPreviewNum = m_previewNum;

            // add previews if the add synth feature is NOT enabled; to show the scene with synth node for comparison
            if (!Params.addSynthNode && Params.addSynthSceneNum <= m_previewNum)
            {
                m_previewNum += Params.addSynthSceneNum;
            }

            else if (!Params.addSynthNode && Params.addContextSceneNum > m_previewNum)
            {
                Params.addSynthNode = false;
                TextDialog.textDebug("Specified add synth node scene number larger than preview number, no scenes with synth node are added.");
            }


            // add previews if the add context feature is enabled, each of them will be enriched scenes of the first given number of results
            if (Params.isUseContext && Params.showBothOriginAndContextView && Params.addContextSceneNum <= m_previewNum)
            {
                m_previewNum += Params.addContextSceneNum;
            }

            else if (Params.isUseContext && Params.showBothOriginAndContextView && Params.addContextSceneNum > m_previewNum)
            {
                Params.isUseContext = false;
                TextDialog.textDebug("Specified add context scene number larger than preview number, no scenes with context are added.");

            }

            //for (int i = 0; i < m_previewNum; ++i)
            //{
            //    TSScene* s = new TSScene(m_models);
            //    m_variations.push_back(s);
            //}

            m_activeVarationId = 0;
        }
        /// <summary>
        /// Load input_name.ssg from Params.resultDirectory
        /// </summary>
        public void loadScene(string input_name)
        {
            m_variations.Clear();

            List<string> sceneNameList = new List<string>(input_name.Split(' '));

            // check scene extension and set proper DB path
            // input scenes number as the variation number each time for now, otherwise will not be shown
            foreach (string sceneName in sceneNameList)
            {
                // result use  stanfordDB models and textures
                //string resultFileName = Params.resultDirectory + sceneName + ".result";
                string ssgFileName = Params.resultDirectory + sceneName + ".ssg";

                if (File.Exists(ssgFileName))
                {
                    SceneSemGraph ssg = new SceneSemGraph(ssgFileName);

                    // .isSelect what use?
                    foreach (MetaModel mm in ssg.m_graphMetaScene.m_metaModellList)
                    {
                        mm.isAlreadyPlaced = true;
                        //m_variations[i].m_graphMetaScene.m_metaModellList[m].isSelected = renderModes[m];
                    }
                    m_variations.Add(ssg);
                }
                else
                {
                    TextDialog.textDebug("Scene file " + sceneName + " does not exist\n");
                }
            }
        }

        /// <summary>
        /// Save m_variations[varationId] as output_name.ssg 
        /// in Params.resultDirectory
        /// </summary>
        public void saveScene(string output_name, int varationId = 0)
        {
            try
            {
                m_variations[varationId].saveGraph(Params.resultDirectory + output_name + ".ssg");
                TextDialog.textDebug("SceneSemGraph: graph saved.\n");

            }
            catch (OutOfMemoryException)
            {
                TextDialog.textDebug("VarationId out of range");
            }

        }



        /// @params int : ID
        /// @return:  result string
        /// <summary>
        /// get m_variations[varationId] result string.
        /// if there has no this varationID, out "modelCount 0"
        /// </summary>
        public string GetScene(int varationId = 0)
        {
            if (m_variations.Count <= varationId)
            {
                //TextDialog.textDebug("varationId OutofRange");
                return "StanfordSceneDatabase\n" + "modelCount 0\n";
            }

            SceneSemGraph ssg = m_variations[varationId];

            StringBuilder sb = new StringBuilder();

            using (StringWriter sw = new StringWriter(sb))
            {
                // catName is "object" line information in DB.ssg 

                MetaScene metaScene = ssg.getMetaScene();
                int modelNum = metaScene.m_metaModellList.Count;
                sw.WriteLine("modelCount " + modelNum);
                for (int i = 0; i < modelNum; i++)
                {
                    MetaModel md = metaScene.m_metaModellList[i];
                    sw.WriteLine("newModel " + i + " " + md.name + " " + md.catName);
                    sw.WriteLine("transform " + string.Format("{0:F6}", md.transformation.m00) + " " + string.Format("{0:F6}", md.transformation.m10) + " " + string.Format("{0:F6}", md.transformation.m20) + " " + string.Format("{0:F6}", md.transformation.m30) + " "
                        + string.Format("{0:F6}", md.transformation.m01) + " " + string.Format("{0:F6}", md.transformation.m11) + " " + string.Format("{0:F6}", md.transformation.m21) + " " + string.Format("{0:F6}", md.transformation.m31) + " "
                        + string.Format("{0:F6}", md.transformation.m02) + " " + string.Format("{0:F6}", md.transformation.m12) + " " + string.Format("{0:F6}", md.transformation.m22) + " " + string.Format("{0:F6}", md.transformation.m32) + " "
                        + string.Format("{0:F6}", md.transformation.m03) + " " + string.Format("{0:F6}", md.transformation.m13) + " " + string.Format("{0:F6}", md.transformation.m23) + " " + string.Format("{0:F6}", md.transformation.m33));
                }
            }


            return "StanfordSceneDatabase\n" + sb.ToString();
        }




        // input: out-scene.txt
        // output: m_variarions (the generated ssgs)
        // LDS the out-scene.txt
        public void runOneEvolutionStep()
        {
            // get active tsg
            string filename = "out-scene.txt";

            m_textSemGraphManager.LoadSELFromOutput(filename, m_sceneGenerator.getRelationManager());

            //m_variations.Add(new SceneSemGraph());

            for (int i = 0; i < m_textSemGraphManager.m_textSemGraphs.Count; ++i)
            {
                TextSemGraph activeTextSemGraph = m_textSemGraphManager.m_textSemGraphs[i];

                m_sceneGenerator.updateCurrentTextGraph(activeTextSemGraph);

                //m_variations[m_activeVarationId].m_isLoadFromFile = false;
                if (m_variations.Count > m_activeVarationId)
                    m_sceneGenerator.updateCurrentTSScene(m_variations[m_activeVarationId]);
                //else
                //    m_sceneGenerator.updateCurrentTSScene(new SceneSemGraph());

                if (!activeTextSemGraph.m_isCommand)
                {
                    activeTextSemGraph.printGraph(string.Format("SelfData/TextSSGlog/sentence{0}.ssg", i));

                    //int topSSGNum = m_initPreviewNum;
                    int targetMatchNum = 20;
                    List<SceneSemGraph> scenes = m_sceneGenerator.generateTSScenes(targetMatchNum);

                    m_variations = scenes;
                    m_activeVarationId = 0;


                    // random a activeVarationId
                    //m_activeVarationId = Util.GenRandomInt(0, 3);
                    //m_variations[0] = m_variations[m_activeVarationId];
                    //m_activeVarationId = 0;

                    //m_variations[m_activeVarationId] = LayoutPlanner.ProcessLayoutByUnalignedRelation(m_variations[m_activeVarationId]);

                }
                else
                {
                    // command verb process
                }

            }

        }

        /// <summary>
        /// clear the scene
        /// </summary>
        public void Clear()
        {
            m_variations.Clear();

            m_activeVarationId = 0;

            m_sceneGenerator.Clear();
        }

        public void DeleteObject(string objectName)
        {
            if (m_variations.Count > m_activeVarationId)
            {
                // Delete Node and Edges
                if (m_variations[m_activeVarationId].deleteObject(objectName))
                {
                    TextDialog.textDebug(objectName + " delete successfully!");
                }
                else
                {
                    TextDialog.textDebug(objectName + "doesn't find!", true);
                }
            }
        }

        // updateOp
        public Dictionary<int,int> getRelatedModels(int metaModelIndex)
        {
            if (m_variations.Count <= m_activeVarationId) return null;

            return m_variations[m_activeVarationId].getSupportModels(metaModelIndex);
        }
    }
}
